#!/bin/sh

# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Timeouts in msec
readonly SIGTERM_TIMEOUT=2500
readonly SIGKILL_TIMEOUT=2000

# Send SIGTERM once to all processes that match regex in $1, then wait for
# them all to terminate.  If processes matching $1 are still running after
# SIGTERM_TIMEOUT msec they are all sent SIGKILL once.  If processes matching
# $1 are still present after SIGKILL_TIMEOUT msec a message is logged.
term_process() {
  local process="$1"

  pkill "$process"
  local i=0
  while [ $i -lt $SIGTERM_TIMEOUT ]; do
    pid=$(pgrep "$process")
    if [ $? -ne 0 ] ; then
      return
    fi
    sleep .1
    i=$((i + 100))
  done

  logger -t "term_process($process)" \
      "PIDs ["$pid"] did not terminate, sending SIGKILL"

  pkill -KILL "$process"
  i=0
  while [ $i -lt $SIGKILL_TIMEOUT ]; do
    pid=$(pgrep "$process")
    if [ $? -ne 0 ] ; then
      return
    fi
    sleep .1
    i=$((i + 100))
  done
  logger -t "term_process($process)" "PIDs ["$pid"] not dead after SIGKILL"
}


# For a given mountpoint, this will kill all processes with open files
# on that mountpoint so that it can be unmounted. It starts off by sending
# a TERM and if the process hasn't exited quickly enough it will send KILL.
#
# Since a typical shutdown should have no processes with open files on a
# partition that we care about at this point, we log the set of processes
# to /var/log/shutdown_force_kill_processes
kill_with_open_files_on() {
  PIDS=$(lsof -t $@ | sort -n | uniq)
  if [ -z "$PIDS" ] ; then
    return  # The typical case; no open files at this point.
  fi

  # PIDS should have been empty. Since it is not, we log for future inspection.
  lsof $@ > /var/log/shutdown_force_kill_processes

  # First try a gentle kill -TERM
  for i in 1 2 3 4 5 6 7 8 9 10; do
    for pid in $PIDS ; do
      ! kill -TERM $pid
    done
    PIDS=$(lsof -t $@ | sort -n | uniq)
    if [ -z "$PIDS" ] ; then
      return
    fi
    sleep .1
  done

  # Now kill -KILL as necessary
  PIDS=$(lsof -t $@ | sort -n | uniq)
  for i in 1 2 3 4 5 6 7 8 9 10; do
    for pid in $PIDS ; do
      ! kill -KILL $pid
    done
    PIDS=$(lsof -t $@ | sort -n | uniq)
    if [ -z "$PIDS" ] ; then
      return
    fi
    sleep .1
  done
}


